﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xplang.abstractions;
using xplang.run;
using xplang.expression;
using xplang.errors;

namespace xplang.rtl.operators
{

  public class EquatableClass : NativeClass
  {

    public const String opAttrib = "=";
    public const String opEQ = "==";
    public const String opNE = "!=";
    public ClassMethod mAttrib;
    public ClassMethod mEQ;
    public ClassMethod mNE;

    public EquatableClass()
      : base(RTL.rtl, "Equatable")
    {
      genericParams = new GenericParamDecl[] 
      { 
        xplang.rtl.RTL.rightParamType
      };
      inheritance = new ClassRef[] { };
    }

    public override void registerMembers()
    {
      mAttrib = new AttribMethod(this, Modifier.None,
        xplang.rtl.RTL.booleanClass.getRef(null),
        opAttrib,
        new Variable[] { xplang.rtl.RTL.rightParam });
      methods.Add(mAttrib);
      mEQ = new NativeClassMethod(this, Modifier.None,
        xplang.rtl.RTL.booleanClass.getRef(null),
        opEQ,
        new Variable[] { xplang.rtl.RTL.rightParam });
      methods.Add(mEQ);
      mNE = new NativeClassMethod(this, Modifier.None,
        xplang.rtl.RTL.booleanClass.getRef(null),
        opNE,
        new Variable[] { xplang.rtl.RTL.rightParam });
      methods.Add(mNE);

      xplang.rtl.RTL.equatableClass.mEQ.registerImplementation(this, impEQ);
      xplang.rtl.RTL.equatableClass.mNE.registerImplementation(this, impNE);
    }

    private Value impEQ(Value[] heap, ref FlowState state)
    {
      return new Value(xplang.rtl.RTL.booleanClass.getRef(null), heap[0].pointer==heap[1].pointer);
    }

    private Value impNE(Value[] heap, ref FlowState state)
    {
      return new Value(xplang.rtl.RTL.booleanClass.getRef(null), heap[0].pointer != heap[1].pointer);
    }

    public override object newInstance()
    {
      throw new AbstractInstanciation();
    }

    public override Value getAttributeValue(Value _this, Variable variable)
    {
      throw new NotImplementedException();
    }

    public override void setAttributeValue(Value _this, Variable variable, Value obj)
    {
      throw new NotImplementedException();
    }
  }

  public class AttribMethod : NativeClassMethod
  {
    public AttribMethod(ClassDecl declaringClass, Modifier modifier, ClassRef returnType, String name, Variable[] parameters)
      : base(declaringClass, modifier, returnType, name, parameters)
    {
    }
    public override bool supportTheseParameters(ClassRef[] paramTypes, ClassRef[] mappings)
    {
      if (paramTypes.Length > 0 && declaringClass == paramTypes[0].getClassDecl())
        return true;
      int n = paramTypes.Length;
      if (n > parameters.Length)
        return false;
      for (int i = 0; i < n; i++)
      {
        ClassRef pTry = paramTypes[i];
        ClassRef pDef = mappings[i];//        parameters[i].type.getGenericMappings();
        if (pTry != pDef)
          return false;
        //if (pDef.supports(pTry, new ClassRef[] { }))
        //return true;
      }
      return true;
    }
  }
}
